import { stringUtils } from 'my-ts-core';

import { GeneralConfig } from '../config';
import { BrowserStorage } from '../storage';
import { RememberMeService } from './remember-me-service';
import type { User } from './user';

/**
 * The service provides method against authentication.
 *
 * Current active user info is saved in local storage with key [GeneralConfig.localUserInfoStorageKey].
 * This is used to determine if user is logged in or not.
 *
 * The active user access token is saved in local storage with key [GeneralConfig.localAccessTokenStorageKey].
 *
 * IMPORTANT!!!
 * Never ever saves user plain password on client side!!!
 */
export class AuthenticationService {
  static get currentUser(): User | null {
    return AuthenticationService._currentUser;
  }

  static get currentUsername(): string | null {
    return AuthenticationService._currentUsername;
  }

  static get isAuthenticated(): boolean {
    return AuthenticationService._isAuthenticated;
  }

  // Loads the user from session storage at the first time.
  private static _currentUser: User | null = RememberMeService.rememberMe
    ? (BrowserStorage.loadLocalData(GeneralConfig.localUserInfoStorageKey, null) as User | null)
    : (BrowserStorage.loadSessionData(GeneralConfig.localUserInfoStorageKey, null) as User | null);

  private static _currentUsername: string | null = BrowserStorage.loadLocalData(
    GeneralConfig.localCurrentUsernameStorageKey,
  );

  // Sets authentication status based on local user and token info.
  private static _isAuthenticated: boolean = this._currentUser != null;

  /**
   * Notifies the observer that user has logged out.
   * @param user The user object that will be sent to all observers.
   */
  saveUserInfo(user: any): void {
    AuthenticationService._isAuthenticated = true;
    AuthenticationService._currentUser = user;

    if (RememberMeService.rememberMe === true) {
      // Removes session data just in case.
      BrowserStorage.removeSessionData(GeneralConfig.localUserInfoStorageKey);

      // If users checks 'remember me' the data will be saved in local storage.
      BrowserStorage.saveLocalData(GeneralConfig.localUserInfoStorageKey, user);
    } else {
      // Removes the local data just in case.
      BrowserStorage.removeLocalData(GeneralConfig.localUserInfoStorageKey);

      // If users does NOT check 'remember me' the data will be saved in session storage.
      // Onces user closes the browser the session storage will be auto cleared.
      BrowserStorage.saveSessionData(GeneralConfig.localUserInfoStorageKey, user);
    }
  }

  /**
   * Saves current username. This is for logic form with saved username.
   */
  saveCurrentUsername(username?: string | null): void {
    // [currentUser] will be null if user is not logged in yet.
    if (
      stringUtils.isNullOrUndefinedOrEmptyString(username) &&
      AuthenticationService._currentUser != null
    ) {
      username = AuthenticationService._currentUser.username;
    }

    if (!stringUtils.isNullOrUndefinedOrEmptyString(username)) {
      BrowserStorage.saveLocalData(GeneralConfig.localCurrentUsernameStorageKey, username);
    }
  }

  /**
   * Removes current username. This is for logic form with saved username.
   */
  removeCurrentUsername(): void {
    BrowserStorage.removeLocalData(GeneralConfig.localCurrentUsernameStorageKey);
  }

  /**
   * Notifies the observer that user has logged out and clears the redirectUrl.
   */
  removeUserInfo(): void {
    BrowserStorage.removeLocalData(GeneralConfig.localUserInfoStorageKey);
    BrowserStorage.removeSessionData(GeneralConfig.localUserInfoStorageKey);
    AuthenticationService._isAuthenticated = false;
    AuthenticationService._currentUser = null;
    // redirectUrl = null;
  }
}
